#!/usr/bin/env python3
import pandas as pd 
import numpy as np 
import os 
from datetime import datetime 


def comprehensive_data_preprocessing(input_file, output_file=None): 
    """ 
    完整的数据预处理流程 
    
    参数: 
    input_file: 输入CSV文件路径 
    output_file: 输出文件路径（可选） 
    """ 
    
    # 1. 读取数据 
    print(f"正在读取数据: {input_file}") 
    try: 
        df = pd.read_csv(input_file, encoding='utf-8', sep=';')  # 注意：数据集中使用分号作为分隔符
    except: 
        try: 
            df = pd.read_csv(input_file, encoding='gbk', sep=';') 
        except: 
            print("尝试使用其他编码...") 
            df = pd.read_csv(input_file, encoding='gb18030', sep=';') 
    
    print(f"原始数据: {df.shape[0]}行, {df.shape[1]}列") 
    
    # 2. 数据探索 
    print("\n=== 数据探索 ===") 
    print("数据概览:") 
    print(df.info()) 
    
    # 3. 缺失值处理 
    print("\n=== 缺失值处理 ===") 
    missing_percent = (df.isnull().sum() / len(df)) * 100 
    missing_data = pd.DataFrame({ 
        '缺失数量': df.isnull().sum(), 
        '缺失比例%': missing_percent 
    }) 
    print(missing_data[missing_data['缺失数量'] > 0]) 
    
    # 4. 重复值检查 
    print("\n=== 重复值检查 ===") 
    duplicate_rows = df.duplicated().sum() 
    print(f"完全重复行数: {duplicate_rows}") 
    
    # 5. 关键字段格式转换 
    print("\n=== 格式转换 ===") 
    
    # 转换时间字段 
    time_columns = ['distinct_usermsg.run_time', 'distinct_usermsg.open_time'] 
    for col in time_columns: 
        if col in df.columns: 
            df[col] = pd.to_datetime(df[col], errors='coerce') 
            print(f"已转换 {col} 为datetime格式") 
    
    # 6. 主要预处理：去重 
    print("\n=== 执行去重规则 ===") 
    
    # 规则1: 按phone_no分组，保留run_time最大的记录 
    print("执行规则1: 按用户编号分组，保留状态变更时间最大的记录...") 
    df['run_time_temp'] = pd.to_datetime(df['distinct_usermsg.run_time']) 
    idx_max = df.groupby('distinct_usermsg.phone_no')['run_time_temp'].idxmax() 
    df_processed = df.loc[idx_max].copy() 
    df_processed.drop('run_time_temp', axis=1, inplace=True) 
    
    print(f"规则1处理后行数: {len(df_processed)}") 
    
    # 规则2: 如果仍然重复，删除品牌名称为"模拟有线电视"的数据 
    print("执行规则2: 处理仍然重复的记录...") 
    
    # 检查重复 
    duplicates_after_rule1 = df_processed[df_processed.duplicated('distinct_usermsg.phone_no', keep=False)] 
    
    if len(duplicates_after_rule1) > 0: 
        print(f"发现 {len(duplicates_after_rule1['distinct_usermsg.phone_no'].unique())} 个重复用户编号") 
        
        # 方法1: 先删除模拟有线电视，然后保留第一条 
        mask_simulate = df_processed['distinct_usermsg.sm_name'] == '模拟有线电视' 
        mask_duplicate = df_processed.duplicated('distinct_usermsg.phone_no', keep=False) 
        
        # 需要删除的记录：既是重复又是模拟有线电视 
        to_delete = mask_duplicate & mask_simulate 
        
        print(f"标记删除 {to_delete.sum()} 条'模拟有线电视'记录") 
        df_processed = df_processed[~to_delete] 
        
        # 对于仍然重复的记录，保留第一条 
        df_processed = df_processed.drop_duplicates(subset=['distinct_usermsg.phone_no'], keep='first') 
    
    print(f"规则2处理后行数: {len(df_processed)}") 
    
    # 7. 数据质量增强 
    print("\n=== 数据质量增强 ===") 
    
    # 提取地址信息 
    if 'distinct_usermsg.addressoj' in df_processed.columns: 
        # 可以尝试提取省市区信息 
        df_processed['province'] = df_processed['distinct_usermsg.addressoj'].apply( 
            lambda x: x.split('省')[0] + '省' if isinstance(x, str) and '省' in x else '' 
        ) 
        df_processed['city'] = df_processed['distinct_usermsg.addressoj'].apply( 
            lambda x: x.split('市')[0] + '市' if isinstance(x, str) and '市' in x else '' 
        ) 
    
    # 计算用户年龄（如果有开户时间） 
    if 'distinct_usermsg.open_time' in df_processed.columns: 
        df_processed['customer_age_days'] = ( 
            pd.to_datetime('today') - df_processed['distinct_usermsg.open_time'] 
        ).dt.days 
    
    # 8. 保存结果 
    if output_file: 
        df_processed.to_csv(output_file, index=False, encoding='utf-8', sep=';') 
        print(f"\n处理后的数据已保存到: {output_file}") 
    
    # 9. 生成处理报告 
    generate_preprocessing_report(df, df_processed) 
    
    return df_processed 


def generate_preprocessing_report(original_df, processed_df): 
    """生成预处理报告"""
    
    report = { 
        '处理时间': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 
        '原始数据行数': len(original_df), 
        '原始数据列数': original_df.shape[1], 
        '处理后数据行数': len(processed_df), 
        '删除行数': len(original_df) - len(processed_df), 
        '删除比例%': round((1 - len(processed_df)/len(original_df)) * 100, 2), 
        '唯一用户数': processed_df['distinct_usermsg.phone_no'].nunique(), 
        '品牌数量': processed_df['distinct_usermsg.sm_name'].nunique(), 
        '用户等级数量': processed_df['distinct_usermsg.owner_name'].nunique(), 
    } 
    
    print("\n" + "="*50) 
    print("数据预处理报告") 
    print("="*50) 
    for key, value in report.items(): 
        print(f"{key}: {value}") 
    
    # 额外添加品牌分布统计
    print("\n品牌分布:")
    brand_counts = processed_df['distinct_usermsg.sm_name'].value_counts()
    print(brand_counts)
    
    # 额外添加状态分布统计
    print("\n用户状态分布:")
    status_counts = processed_df['distinct_usermsg.run_name'].value_counts()
    print(status_counts)
    
    return report 


# 使用示例 
if __name__ == "__main__": 
    # 设置文件路径 
    input_csv = "mediamatch_usermsg_first20000.csv"  # 替换为你的实际文件路径 
    output_csv = "预处理后的广电用户数据.csv" 
    
    # 执行预处理 
    df_clean = comprehensive_data_preprocessing( 
        input_file=input_csv, 
        output_file=output_csv 
    ) 
    
    # 显示处理后的数据样例 
    print("\n=== 处理后的数据样例 ===") 
    print(df_clean.head())